package com.smart.mcuservice;

import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Toast;

import com.android.internal.policy.cvte.EthernetControl;
import com.smart.uart.SerialDataUtil;
import com.smart.uart.SerialPortUtil;
import com.mstar.android.tvapi.common.TvManager;
import com.mstar.android.tvapi.common.exception.TvCommonException;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by wuguitong on 2016/11/22.
 */
public class SmartMcuService extends Service{
    private static final int DELAY_TIME = 30000;
    final RemoteCallbackList<ISmartMcuReceCallback> mCallbacks = new RemoteCallbackList <ISmartMcuReceCallback>();
    private boolean isMcuALive = false;
    private boolean isSetUsbSuccess = false;
    private boolean isSetGpioSuccess = false;
    private boolean isTeatUartSuccess = false;
    private boolean isTestNetPortSuccess = false;
    private boolean isReceUartRet = false;
    private Timer updateStatusTimer = null;
    private String mcuVersion = null;
    private SmartMcuServiceBinder mBinder = null;
    private Handler mControlHandler = null;
    private Handler mMcuStatusHandler = null;
    private Handler mUpdateProHandler = null;
    private Context mContext = null;
    private SerialPortUtil mSerialPortUtil = null;
    private SerialDataUtil.McuBinData mcuBinData = null;
    private EthernetControl sEthernetControl = null;
    private Handler handler = new Handler();
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (sEthernetControl != null) {
                sEthernetControl.setEnabled(false);
                sEthernetControl.setEnabled(true);
            }
            handler.postDelayed(this,DELAY_TIME);
        }
    };
    private SerialPortUtil.OnDataReceiveListener lister = new SerialPortUtil.OnDataReceiveListener() {
        @Override
        public void onDataReceive(byte[] buffer, int size) {
            Log.d("wuguitong", "size = " + size + "\n");
            for(int i =0;i < size;i++)
            {
                Log.d("wuguitong", buffer[i] + "\n");
            }
            if(SerialDataUtil.isMcuUpdating()) {
                if(size == 1){
                    if(updateStatusTimer != null) {
                        updateStatusTimer.cancel();
                        updateStatusTimer = null;
                    }
                    if(buffer[0] == SerialDataUtil.UPDATE_MCU_ACK){
                        switch (SerialDataUtil.getMcuUpdateStatus()){
                            case SerialDataUtil.STATUS_MCU_UPDATE_START:
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_GPIO_INIT:
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_USART_INIT:
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_SEND_ERASE_COMMAND);
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_SEND_ERASE_COMMAND:
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_MASS_ERASE);
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_MASS_ERASE:
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_COMMAND);
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_WRITE_BIN_COMMAND:
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_ADDRESS);
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_WRITE_BIN_ADDRESS:
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_DATA);
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_WRITE_BIN_DATA:
                                if(mcuBinData.isDataEnd()){
                                    mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER);
                                }else {
                                    mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_COMMAND);
                                }
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_GPIO_RECOVER:
                                break;
                            case SerialDataUtil.STATUS_MCU_UPDATE_END:
                                break;
                            default:
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER);
                                break;
                        }
                    }
                    if(buffer[0] == SerialDataUtil.UPDATE_MCU_NACK){
                        mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER);
                    }
                }
            }else {
                int datasize = SerialDataUtil.decodeReceBuff(buffer, size);
                for (int i = 0; i < datasize; i++) {
                    SerialDataUtil.ReceData data = SerialDataUtil.getCurrentReceData();
                    if (data != null) {
                        Message msg = mControlHandler.obtainMessage(data.getControlData());
                        Bundle mBundle = new Bundle();
                        mBundle.putByteArray(SerialDataUtil.DATA, data.getReceData());
                        msg.setData(mBundle);
                        msg.sendToTarget();
                        McuReceCallback(data.getControlData(), data.getReceData(), data.getReceData().length);
                    }
                }
            }
        }
    };
    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("wuguitong","onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("wuguitong", "onBind");
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
        SerialDataUtil.initSerialDataUtil();
        mSerialPortUtil = SerialPortUtil.getInstance();
        mSerialPortUtil.setOnDataReceiveListener(lister);
        mBinder = new SmartMcuServiceBinder();
        if (sEthernetControl == null) {
            sEthernetControl = new EthernetControl();
            sEthernetControl.getSystemService(mContext);
        }
        handler.postDelayed(runnable,DELAY_TIME);
        mControlHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg) {
                Bundle receBundle = msg.getData();
                byte[] receBytes;
                //Log.d("wuguitong","handleMessage" + (msg.what&0x0f));
                switch (msg.what)
                {
                    case SerialDataUtil.E_RECE_GPIO_STATUS_CONTROL:
                        isSetGpioSuccess = true;
                        break;
                    case SerialDataUtil.E_RECE_USB_SWITCH_CONTROL:
                        isSetUsbSuccess = true;
                        break;
                    case SerialDataUtil.E_RECE_MCU_ALIVE_CONTROL:
                        isMcuALive = true;
                        break;
                    case SerialDataUtil.E_RECE_TEST_UART_CONTROL:
                        isReceUartRet = true;
                        receBytes = receBundle.getByteArray(SerialDataUtil.DATA);
                        if(receBytes[0] == 1){
                            isTeatUartSuccess = true;
                        }else {
                            isTeatUartSuccess = false;
                        }
                        break;
                    case SerialDataUtil.E_RECE_TEST_NET_PORT_CONTROL:
                        receBytes = receBundle.getByteArray(SerialDataUtil.DATA);
                        if((receBytes[0] & 0x0F) == 1){
                            isTestNetPortSuccess = true;
                        }else {
                            isTestNetPortSuccess = false;
                        }
                        break;
                    case SerialDataUtil.E_RECE_SOFTWARE_VERSION_CONTROL:
                        receBytes = receBundle.getByteArray(SerialDataUtil.DATA);
                        mcuVersion = new String(receBytes);
                        break;
                    default:
                        break;
                }
                super.handleMessage(msg);
            }
        };
        mMcuStatusHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                byte[] writeBytes;
                switch (msg.what){
                    //update mcu
                    case SerialDataUtil.MSG_MCU_UPDATE_START:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_START);
                        mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_INIT);
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_GPIO_INIT:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_GPIO_INIT);
                        new Thread(){
                            @Override
                            public void run() {
                                try {
                                    TvManager.getInstance().setGpioDeviceStatus(79, false);
                                    Thread.sleep(10);
                                    TvManager.getInstance().setGpioDeviceStatus(80, true);
                                    Thread.sleep(10);
                                    TvManager.getInstance().setGpioDeviceStatus(79, true);
                                    Thread.sleep(100);
                                } catch (TvCommonException e) {
                                    e.printStackTrace();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_USART_INIT);
                            }
                        }.start();
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_USART_INIT:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_USART_INIT);
                        writeBytes =new byte[1];
                        writeBytes[0] = (byte)0x7F;
                        mSerialPortUtil.sendBuffer(writeBytes);
                        if(updateStatusTimer != null) {
                            updateStatusTimer.cancel();
                            updateStatusTimer = null;
                        }
                        updateStatusTimer = new Timer();
                        updateStatusTimer.schedule(new UpdateMcuStatusTimerTask(), 1000);
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_SEND_ERASE_COMMAND:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_SEND_ERASE_COMMAND);
                        writeBytes =new byte[2];
                        writeBytes[0] = (byte)0x44;
                        writeBytes[1] = (byte)0xBB;
                        mSerialPortUtil.sendBuffer(writeBytes);
                        if(updateStatusTimer != null) {
                            updateStatusTimer.cancel();
                            updateStatusTimer = null;
                        }
                        updateStatusTimer = new Timer();
                        updateStatusTimer.schedule(new UpdateMcuStatusTimerTask(), 1000);
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_MASS_ERASE:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_MASS_ERASE);
                        writeBytes =new byte[3];
                        writeBytes[0] = (byte)0xFF;
                        writeBytes[1] = (byte)0xFF;
                        writeBytes[2] = (byte)0x00;
                        mSerialPortUtil.sendBuffer(writeBytes);
                        if(updateStatusTimer != null) {
                            updateStatusTimer.cancel();
                            updateStatusTimer = null;
                        }
                        updateStatusTimer = new Timer();
                        updateStatusTimer.schedule(new UpdateMcuStatusTimerTask(), 25000);
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_COMMAND:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_WRITE_BIN_COMMAND);
                        writeBytes =new byte[2];
                        writeBytes[0] = (byte)0x31;
                        writeBytes[1] = (byte)0xCE;
                        mSerialPortUtil.sendBuffer(writeBytes);
                        if(updateStatusTimer != null) {
                            updateStatusTimer.cancel();
                            updateStatusTimer = null;
                        }
                        updateStatusTimer = new Timer();
                        updateStatusTimer.schedule(new UpdateMcuStatusTimerTask(), 3000);
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_ADDRESS:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_WRITE_BIN_ADDRESS);
                        writeBytes = mcuBinData.getAddressCom();
                        if(writeBytes == null){
                            mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER);
                        }else {
                            mSerialPortUtil.sendBuffer(writeBytes);
                            if(updateStatusTimer != null) {
                                updateStatusTimer.cancel();
                                updateStatusTimer = null;
                            }
                            updateStatusTimer = new Timer();
                            updateStatusTimer.schedule(new UpdateMcuStatusTimerTask(), 3000);
                        }
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_WRITE_BIN_DATA:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_WRITE_BIN_DATA);
                        writeBytes = mcuBinData.getDataBlock();
                        if(writeBytes == null){
                            mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER);
                        }else {
                            mSerialPortUtil.sendBuffer(writeBytes);
                            if(updateStatusTimer != null) {
                                updateStatusTimer.cancel();
                                updateStatusTimer = null;
                            }
                            updateStatusTimer = new Timer();
                            updateStatusTimer.schedule(new UpdateMcuStatusTimerTask(), 3000);
                        }
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_GPIO_RECOVER);
                        new Thread(){
                            @Override
                            public void run() {
                                try {
                                    TvManager.getInstance().setGpioDeviceStatus(79, false);
                                    TvManager.getInstance().setGpioDeviceStatus(80, false);
                                    TvManager.getInstance().setGpioDeviceStatus(79, true);
                                } catch (TvCommonException e) {
                                    e.printStackTrace();
                                }
                                mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_END);
                            }
                        }.start();
                        break;
                    case SerialDataUtil.MSG_MCU_UPDATE_END:
                        SerialDataUtil.setMcuUpdateStatus(SerialDataUtil.STATUS_MCU_UPDATE_END);
                        SerialDataUtil.setMcuOutOfUpdating();
                        byte[] bytes = new byte[1];
                        if(mcuBinData.isDataEnd()) {
                            Log.d("wuguitong","update ok");
                            bytes[0] = SerialDataUtil.MCU_UPDATE_STATUS_SUCCESS;
                            McuReceCallback(SerialDataUtil.MCU_UPDATE_STATUS_CONTROL, bytes,1);
                            mUpdateProHandler.sendEmptyMessage(SerialDataUtil.MCU_UPDATE_STATUS_SUCCESS);
                        }else{
                            Log.d("wuguitong","update fail");
                            bytes[0] = SerialDataUtil.MCU_UPDATE_STATUS_FAIL;
                            McuReceCallback(SerialDataUtil.MCU_UPDATE_STATUS_CONTROL,bytes,1);
                            mUpdateProHandler.sendEmptyMessage(SerialDataUtil.MCU_UPDATE_STATUS_FAIL);
                        }
                        mcuBinData = null;
                        break;
                    default:
                        break;
                }
                super.handleMessage(msg);
            }
        };
        mUpdateProHandler =  new Handler() {
            @Override
            public void handleMessage(Message msg) {
                AlertDialog.Builder builder;
                AlertDialog dialog;
                switch (msg.what){
                    case SerialDataUtil.MCU_UPDATE_STATUS_FAIL:
                        builder  = new AlertDialog.Builder(mContext);
                        builder.setTitle("Update Mcu") ;
                        builder.setMessage("Update Smart Mcu FW Fail!") ;
                        builder.setPositiveButton("OK", null);
                        dialog = builder.create();
                        dialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
                        dialog.show();
                        break;
                    case SerialDataUtil.MCU_UPDATE_STATUS_SUCCESS:
                        builder  = new AlertDialog.Builder(mContext);
                        builder.setTitle("Update Mcu" ) ;
                        builder.setMessage("Update Smart Mcu FW Success!") ;
                        builder.setPositiveButton("OK", null);
                        dialog = builder.create();
                        dialog.getWindow().setType((WindowManager.LayoutParams.TYPE_SYSTEM_ALERT));
                        dialog.show();
                        break;
                    case SerialDataUtil.MCU_UPDATE_STATUS_UPDATING:
                        Toast.makeText(mContext,"Update Smart Mcu FW is Updating!",Toast.LENGTH_LONG).show();
                        break;
                    case SerialDataUtil.MCU_UPDATE_STATUS_UPDATE_START:
                        Toast.makeText(mContext,"Update Smart MCU Statr",Toast.LENGTH_LONG).show();
                        break;
                    case SerialDataUtil.MCU_UPDATE_STATUS_NOT_FILE:
                        Toast.makeText(mContext,"Nof Find Update File SmartMcuTestFW.bin",Toast.LENGTH_LONG).show();
                        break;
                    default:
                        break;
                }
            }
        };
        Log.d("wuguitong","onCreate");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        isMcuALive = false;
        isSetGpioSuccess = false;
        isSetUsbSuccess = false;
        isTeatUartSuccess = false;
        isTestNetPortSuccess = false;
        isReceUartRet = false;
        mcuVersion = null;
        mSerialPortUtil.closeSerialPort();
        SerialPortUtil.deleteInstance();
        mSerialPortUtil = null;
        mBinder = null;
        mControlHandler = null;
        mUpdateProHandler = null;
        mMcuStatusHandler = null;
        Log.d("wuguitong","onDestroy");
    }
    class UpdateMcuStatusTimerTask extends TimerTask {
        @Override
        public void run() {
            Log.d("wuguitong","UpdateMcuStatusTimerTask");
            mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_GPIO_RECOVER);
            updateStatusTimer.cancel();
            updateStatusTimer = null;
        }
    }
    public class SmartMcuServiceBinder extends ISmartMcuService.Stub{
        @Override
        public boolean isMcuALive() throws RemoteException {
            if(mSerialPortUtil == null || SerialDataUtil.isMcuUpdating())
                return false;
            for(int j = 0;j < 2 ;j++) {
                mSerialPortUtil.sendBuffer(SerialDataUtil.getSendMcuALiveBuf());
                for (int i = 0; i < 3; i++) {
                    Delay(100);
                    if (isMcuALive == true) {
                        isMcuALive = false;
                        return true;
                    }
                }
            }
            isMcuALive = false;
            return false;
        }

        @Override
        public boolean setGpioStatus(int port, boolean status) throws RemoteException {
            if(mSerialPortUtil == null || SerialDataUtil.isMcuUpdating())
                return false;
            byte data = 0X00;
            data |= status ? 0X80:0X00;
            data |= (port & 0X7F);
            for(int j = 0;j < 2 ;j++) {
                mSerialPortUtil.sendBuffer(SerialDataUtil.getSendGpioStatusBuf(data));
                for (int i = 0; i < 3; i++) {
                    Delay(100);
                    if (isSetGpioSuccess == true) {
                        isSetGpioSuccess = false;
                        return true;
                    }
                }
            }
            isSetGpioSuccess = false;
            return false;
        }

        @Override
        public boolean setUsbSwitch(int port) throws RemoteException {
            if(mSerialPortUtil == null || SerialDataUtil.isMcuUpdating())
                return false;
            byte data = 0X00;
            data = (byte)port;
            for(int j = 0;j < 2 ;j++) {
                mSerialPortUtil.sendBuffer(SerialDataUtil.getSendUsbSwitchBuf(data));
                for (int i = 0; i < 3; i++) {
                    Delay(100);
                    if (isSetUsbSuccess == true) {
                        isSetUsbSuccess = false;
                        return true;
                    }
                }
            }
            isSetUsbSuccess = false;
            return false;
        }

        @Override
        public String getSoftwareVersion() throws RemoteException {
            if(mSerialPortUtil == null || SerialDataUtil.isMcuUpdating())
                return null;
            for(int j = 0;j < 2 ;j++) {
                mSerialPortUtil.sendBuffer(SerialDataUtil.getSendSoftwareVersionBuf());
                for (int i = 0; i < 3; i++) {
                    Delay(100);
                    if (mcuVersion != null) {
                        return mcuVersion;
                    }
                }
            }
            return null;
        }

        @Override
        public boolean testMcuUart() throws RemoteException {
            if(mSerialPortUtil == null || SerialDataUtil.isMcuUpdating())
                return false;
            for(int j = 0;j < 2 ;j++) {
                mSerialPortUtil.sendBuffer(SerialDataUtil.getTestMcuUartBuf());
                for (int i = 0; i < 3; i++) {
                    Delay(100);
                    if (isReceUartRet == true) {
                        isReceUartRet = false;
                        if(isTeatUartSuccess == true) {
                            isTeatUartSuccess = false;
                            return true;
                        }else{
                            return false;
                        }
                    }
                }
            }
            isReceUartRet = false;
            return false;
        }

        @Override
        public boolean testNetPort(int port) throws RemoteException {
            if(mSerialPortUtil == null || SerialDataUtil.isMcuUpdating())
                return false;
            byte data = 0X00;
            data = (byte)port;
            for(int j = 0;j < 2 ;j++) {
                mSerialPortUtil.sendBuffer(SerialDataUtil.getSendNetPortStatusBuf(data));
                for (int i = 0; i < 3; i++) {
                    Delay(100);
                    if (isTestNetPortSuccess == true) {
                        isTestNetPortSuccess = false;
                        return true;
                    }
                }
            }
            isTestNetPortSuccess = false;
            return false;
        }

        @Override
        public boolean updateMcuFW() throws RemoteException {
            if(mSerialPortUtil == null)
                return false;
            if(SerialDataUtil.isMcuUpdating()){
                mUpdateProHandler.sendEmptyMessage(SerialDataUtil.MCU_UPDATE_STATUS_UPDATING);
                return false;
            }
            mcuBinData = SerialDataUtil.getMcuBinData();
            if(mcuBinData == null) {
                mUpdateProHandler.sendEmptyMessage(SerialDataUtil.MCU_UPDATE_STATUS_NOT_FILE);
                return false;
            }
            mUpdateProHandler.sendEmptyMessage(SerialDataUtil.MCU_UPDATE_STATUS_UPDATE_START);
            mMcuStatusHandler.sendEmptyMessage(SerialDataUtil.MSG_MCU_UPDATE_START);
            return true;
        }

        @Override
        public void registerCallback(ISmartMcuReceCallback cb) throws RemoteException {
            if(cb != null) {
                mCallbacks.register(cb);
            }
        }

        @Override
        public void unregisterCallback(ISmartMcuReceCallback cb) throws RemoteException {
            if(cb != null) {
                mCallbacks.unregister(cb);
            }
        }

    }
    private void McuReceCallback(int control,byte[] buffer,int size) {
        final int N = mCallbacks.beginBroadcast();
        for (int i=0; i<N; i++) {
            try {
                mCallbacks.getBroadcastItem(i).actionSmartMcuRece(control,buffer,size);
            }
            catch (RemoteException e) {
                // The RemoteCallbackList will take care of removing
                // the dead object for us.
            }
        }
        mCallbacks.finishBroadcast();
    }
    private void Delay(int ms) {
        try {
            Thread.currentThread();
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
